
package com.zgis.module.data.manager;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.POJONode;
import com.zgis.module.bas.bean.CxRet;
import com.zgis.module.bas.constant.CxKeys;
import com.zgis.module.bas.util.CxJson;
import com.zgis.module.data.service.SvrDataServiceImpl;
import com.zgis.module.db.util.CxParam;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

/**
 * 修改记录:
 * 24-09-29     zhengchaojun             首次创建
 */

/**
 * 类描述：批量操作服务
 */
public class CxSvrBatch
{
    private static final int     SVR_ADD     = 1;
    private static final int     SVR_DEL     = 2;
    private static final int     SVR_UPD     = 3;
    private static final int     SVR_QRY     = 4;
    private static final int     SVR_STAT    = 5;
    private static final int     SVR_PROC    = 6;
    private static final int     SVR_QRYID   = 7;
    private static final int     SVR_QRYID0  = 8;
    private static final String  refIdRef    = "^\\{([0-9]+\\.[0-9]+)\\}\\.id$";
    private static final Pattern refIdRefPtn = Pattern.compile("^\\{([0-9]+\\.[0-9]+)\\}\\.id$");

    /**
     * 执行特定的业务逻辑处理，根据请求参数中的数据类型执行不同的服务操作。
     *
     * @param reqParams 请求参数，包含需要处理的数据。
     * @param dstm      事务管理器
     * @param att       服务数据服务实现，用于执行具体的数据库操作。
     * @return 返回处理结果的对象节点。
     * @throws Exception 如果处理过程中发生任何异常，将抛出异常。
     */
    public ObjectNode run(JsonNode reqParams, PlatformTransactionManager dstm, SvrDataServiceImpl att) throws Exception
    {
        JsonNode   dataAll = reqParams.get(CxKeys.data);
        ObjectNode jo      = CxJson.objectNode();
        ArrayNode  ja      = CxJson.arrayNode();
        int        editNum = 0;
        int        num     = dataAll.size();
        int        i       = 0;

        int      type;
        JsonNode itemBat;
        while (i < num)
        {
            itemBat = dataAll.get(i);
            type = itemBat.get(CxKeys.type).asInt();
            switch (type)
            {
                case 1:
                case 2:
                case 3:
                    ++editNum;
                default:
                    ++i;
            }
        }

        TransactionStatus ts = null;

        try
        {
            if (editNum > 0)
            {
                ts = dstm.getTransaction(new DefaultTransactionDefinition());
            }

            for (i = 0; i < num; ++i)
            {
                itemBat = dataAll.get(i);
                type = itemBat.get(CxKeys.type).asInt();
                JsonNode dataItem = itemBat.get(CxKeys.data);

                int retAt = 0;
                if (itemBat.has(CxKeys.retAt))
                {
                    retAt = itemBat.get(CxKeys.retAt).asInt();
                }

                ObjectNode joBat;
                switch (type)
                {
                    case SVR_ADD:
                        String id = CxParam.getStr(dataItem, CxKeys.id);
                        this.procRefId(dataItem, ja);
                        if (id != null && !id.isEmpty())
                        {
                            joBat = att.insertWithId(dataItem);
                        }
                        else
                        {
                            joBat = att.insertNoId(dataItem);
                        }

                        this.procRet(joBat, retAt, ja);
                        break;
                    case SVR_DEL:
                        joBat = att.del(dataItem);
                        this.procRet(joBat, retAt, ja);
                        break;
                    case SVR_UPD:
                        joBat = att.update(dataItem);
                        this.procRet(joBat, retAt, ja);
                        break;
                    case SVR_QRY:
                        joBat = att.query(dataItem, '1');
                        this.procRet(joBat, retAt, ja);
                        break;
                    case SVR_STAT:
                        this.procRefId(dataItem, ja);
                        joBat = att.stat(dataItem);
                        this.procRet(joBat, retAt, ja);
                        break;
                    case SVR_PROC:
                        joBat = att.callProc(dataItem);
                        this.procRet(joBat, retAt, ja);
                        break;
                    case SVR_QRYID:
                        joBat = att.queryId(dataItem);
                        this.procRet(joBat, retAt, ja);
                        break;
                    case SVR_QRYID0:
                        joBat = att.queryId0(dataItem);
                        this.procRet(joBat, retAt, ja);
                }
            }

            if (dstm != null && ts != null)
            {
                dstm.commit(ts);
            }

            CxRet.setSuccess(jo, ja, false);
            return jo;
        } catch (Exception var21)
        {
            Exception e = var21;
            if (dstm != null && ts != null)
            {
                dstm.rollback(ts);
            }

            throw e;
        }
    }

    /**
     * 处理引用ID的逻辑，将引用的ID替换为实际的数据。
     *
     * @param jo JSON对象节点，包含需要处理的数据。
     * @param ja JSON数组节点，包含所有数据项。
     * @throws Exception 如果处理过程中发生任何异常，将抛出异常。
     */
    private void procRefId(JsonNode jo, ArrayNode ja) throws Exception
    {
        Iterator<Map.Entry<String, JsonNode>> it = jo.fields();

        while (it.hasNext())
        {
            Map.Entry<String, JsonNode> el    = (Map.Entry) it.next();
            String                      key   = (String) el.getKey();
            String                      value = ((JsonNode) el.getValue()).asText();
            Matcher                     match = refIdRefPtn.matcher(value);
            if (match.find())
            {
                boolean found = false;
                value = match.group();
                int num = value.length();
                value = value.substring(1, num - 4);
                String[] arrIdx = value.split("\\.");
                JsonNode joSrc  = ja.get(Integer.parseInt(arrIdx[0]) - 1);
                num = Integer.parseInt(arrIdx[1]) - 1;
                if (joSrc != null && joSrc.has(CxKeys.data))
                {
                    List listSrc = (List) ((POJONode) joSrc.get(CxKeys.data)).getPojo();
                    if (listSrc.size() > num)
                    {
                        Map<String, Object> mapSrc = (Map) listSrc.get(num);
                        if (mapSrc.containsKey(CxKeys.id))
                        {
                            found = true;
                            ((ObjectNode) jo).put(key, mapSrc.get(CxKeys.id).toString());
                        }
                    }
                }

                if (!found)
                {
                    throw new Exception("{errNoId}");
                }
            }
        }

    }

    /**
     * 处理返回结果，根据返回位置将结果放入正确的位置。
     *
     * @param jo    JSON对象节点，包含当前处理的结果。
     * @param retAt 返回位置索引。
     * @param ja    JSON数组节点，包含所有数据项。
     * @throws Exception 如果处理过程中发生任何异常，将抛出异常。
     */
    private void procRet(ObjectNode jo, int retAt, ArrayNode ja) throws Exception
    {
        jo.remove(CxKeys.ret);
        --retAt;
        if (retAt >= 0 && ja.size() > retAt)
        {
            JsonNode dst   = ja.get(retAt);
            JsonNode joSrc = jo.get(CxKeys.data);
            JsonNode joDst = dst.get(CxKeys.data);
            if (joSrc != null && joDst != null)
            {
                List listSrc = (List) ((POJONode) joSrc).getPojo();
                List listDst = (List) ((POJONode) joDst).getPojo();
                if (listSrc.size() == 1 && listDst.size() == 1)
                {
                    Map<String, Object> mapSrc = (Map) listSrc.get(0);
                    Map<String, Object> mapDst = (Map) listDst.get(0);
                    Iterator            var11  = mapSrc.keySet().iterator();

                    while (var11.hasNext())
                    {
                        String key = (String) var11.next();
                        mapDst.put(key, mapSrc.get(key));
                    }
                }
            }

        }
        else
        {
            ja.add(jo);
        }
    }
}